package com.sdlh.demo.script;

import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import lombok.extern.slf4j.Slf4j;
import org.graalvm.polyglot.Context;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class ScriptDemo {
    public static final String SCRIPT = "%s + 65535 / (4096 - %s * 30)";
    public static final String EXPRESSION = "a + 65535 / (4096 - b * 30)";
    public static Expression exp = AviatorEvaluator.compile(EXPRESSION);

    public static void main(String[] args) {
        testTime();
    }

    public static void testTime() {
        ExecutorService executorAviator = Executors.newFixedThreadPool(10);
        ExecutorService executorGraalVM = Executors.newFixedThreadPool(10);

        Random random = new Random();
        // 生成执行的脚本
        int scriptSize = 2000;
        List<String> scriptStrList = new ArrayList<>(scriptSize);
        for (int i = 0; i < scriptSize; i++) {
            double a = getRandomDouble(random);
            double b = getRandomDouble(random);
            String scriptStr = String.format(SCRIPT, a, b);
            scriptStrList.add(scriptStr);
        }

        int count = 10;
        // 统计 Aviator for 循环的执行时间
        // StopWatch stopWatch = new StopWatch();
        CountDownLatch aviatorLatch = new CountDownLatch(count);
        // stopWatch.start("Aviator For Loop");
        long t1 = System.currentTimeMillis();
        HashMap<String, Object> param = new HashMap<>();
        for (int i = 0; i < count; i++) {
            executorAviator.execute(() -> {
                for (String script : scriptStrList) {
//                    testAviator(script);
                    double a = getRandomDouble(random);
                    double b = getRandomDouble(random);
                    param.put("a", a);
                    param.put("b", b);
                    testAviator(script, param);
                }
                // 每完成一个任务，计数减一
                aviatorLatch.countDown();
            });
        }
        try {
            // 等待所有 Aviator 任务完成
            aviatorLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        // stopWatch.stop();
        log.info("aviator耗时{}ms", (System.currentTimeMillis() - t1));

        long t2 = System.currentTimeMillis();
        // 统计 GraalVM for 循环的执行时间
        CountDownLatch graalVMLatch = new CountDownLatch(count);
        // stopWatch.start("GraalVM For Loop");
        for (int i = 0; i < count; i++) {
            executorGraalVM.execute(() -> {
                for (String script : scriptStrList) {
                    testGraalVM(script);
//                    double a = getRandomDouble(random);
//                    double b = getRandomDouble(random);
//                    param.put("a", a);
//                    param.put("b", b);
//                    testGraalVM(EXPRESSION, param);
                }
                // 每完成一个任务，计数减一
                graalVMLatch.countDown();
            });
        }
        try {
            // 等待所有 GraalVM 任务完成
            graalVMLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        // stopWatch.stop();
        log.info("GraalJS耗时{}ms", (System.currentTimeMillis() - t2));

        // 关闭线程池
        executorAviator.shutdown();
        executorGraalVM.shutdown();

        // 打印统计结果
        // System.out.println(stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
    }

    private static double getRandomDouble(Random random) {
        // 生成 [1, 1000) 的整数
        int value = random.nextInt(1000) + 1;
        // 转换为两位小数
        return value / 100.0;
    }

    public static void testAviator(String script, HashMap<String, Object> param) {
        var value = exp.execute(param);
    }

    public static void testAviator(String script) {
        var value = (Double)AviatorEvaluator.execute(script);
    }

    public static void testGraalVM(String script) {
        try (Context context = Context.newBuilder()
                                      .option("engine.WarnInterpreterOnly", "false")
                                      .build()) {
            var value = context.eval("js", script).asDouble();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

}
